#include "stdafx.h"
#include <limits.h>
#include "Document.h"
#include "ISettings.h"
#include "Support.h"
#include <wx/ffile.h>
#include <gtest/gtest.h>
#include <tuple>

class NoSettings: public ISettings {
public:
	virtual bool GetSettingBool(const wxString& name, bool& value) const { return false; };
	virtual bool GetSettingInt(const wxString& name, int& value) const { return false; };
	virtual bool GetSettingLong(const wxString& name, wxLongLong& value) const { return false; };
	virtual bool GetSettingString(const wxString& name, wxString& value) const { return false; };
};

typedef std::tr1::tuple<wxTextFileType, wxFontEncoding, void*, int> CONFIG;

using ::testing::TestWithParam;
using ::testing::Values;

class DocumentLineEndingTest: public TestWithParam<CONFIG> {
protected:
	// Per-test
	virtual void SetUp() {
		wxString edb;
		if (!RequireEdb(edb)) {
			FAIL() << "Need to copy a registered e.db into this folder for this test to run.";
		}

		pCatalyst = new Catalyst(edb);
		cw = new CatalystWrapper(*pCatalyst);
	};

	virtual void TearDown() {
		if (cw) {delete cw;cw=NULL;}
		if (pCatalyst) {delete pCatalyst;pCatalyst=NULL;}
	};

	Catalyst* pCatalyst;
	CatalystWrapper* cw;
};

TEST_P(DocumentLineEndingTest, SavesCorrectly) {
	CONFIG config = GetParam();
	wxTextFileType configEOL = std::tr1::get<0>(config);
	wxFontEncoding configEncoding = std::tr1::get<1>(config);
	const void* configExpectedBytes = std::tr1::get<2>(config);
	int configExpectedSize = std::tr1::get<3>(config);

	Document m_doc(*cw);
	const NoSettings settings;
	m_doc.CreateNew(settings);
	m_doc.SetPropertyEOL(configEOL);
	m_doc.SetPropertyEncoding(configEncoding);

	m_doc.Insert(0, "This is a line.\nThis is a second line.\n");

	// Save the file, then read it back and compare bytes to what we expect.
	wxFileName path(wxT("testdata/savefile.txt"));
	path.MakeAbsolute();

	m_doc.SaveText(path);

	wxFFile file(wxT("testdata/savefile.txt"), _("rb"));
	file.SeekEnd(0);
	wxFileOffset size = file.Tell();
	file.Seek(0);

	// We expect a certain number of bytes in the output file.
	EXPECT_EQ(configExpectedSize, size);

	char *bytes = new char[size];
	size_t readsize = file.Read(bytes, size);

	ASSERT_EQ(size, readsize) << "Read a different number of bytes than the file size suggested.";

	if(memcmp(bytes, configExpectedBytes, readsize) != 0) {
		ADD_FAILURE() << "Bytes didn't match.";
	}

	delete[] bytes;
}

/* DOS line endings */
unsigned char bytes_crlf_utf16le[82] = {
	0x54, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 
	0x61, 0x00, 0x20, 0x00, 0x6C, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x65, 0x00, 0x2E, 0x00, 
	0x0D, 0x00, 	0x0A, 0x00, 
	0x54, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 
	0x61, 0x00, 0x20, 0x00, 0x73, 0x00, 0x65, 0x00, 0x63, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x64, 0x00, 
	0x20, 0x00, 0x6C, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x65, 0x00, 0x2E, 0x00, 
	0x0D, 0x00, 	0x0A, 0x00
};

unsigned char bytes_crlf_utf16be[82] = {
	0x00, 0x54, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20,
	0x00, 0x61, 0x00, 0x20, 0x00, 0x6C, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x65, 0x00, 0x2E,
	0x00, 0x0D, 0x00, 0x0A,
	0x00, 0x54, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20,
	0x00, 0x61, 0x00, 0x20, 0x00, 0x73, 0x00, 0x65, 0x00, 0x63, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x64,
	0x00, 0x20, 0x00, 0x6C, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x65, 0x00, 0x2E,
	0x00, 0x0D, 0x00, 0x0A
};

unsigned char bytes_crlf_utf32le[164] = {
	0x54, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 
	0x61, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 
	0x0D, 0x00, 	0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 
	0x54, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 
	0x61, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 
	0x20, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 
	0x0D, 0x00, 0x00, 0x00, 	0x0A, 0x00, 0x00, 0x00
};

unsigned char bytes_crlf_utf32be[164] = {
	0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20,
	0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x2E,
	0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0A,
	0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20,
	0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x64,
	0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x2E,
	0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0A
};

INSTANTIATE_TEST_CASE_P(CRLF, 
	DocumentLineEndingTest, 
	Values(
		CONFIG(wxTextFileType_Dos, wxFONTENCODING_CP1252,
			"This is a line.\x0d\x0aThis is a second line.\x0d\x0a", 41),

		CONFIG(wxTextFileType_Dos, wxFONTENCODING_UTF16LE, 
			bytes_crlf_utf16le, 82),

		CONFIG(wxTextFileType_Dos, wxFONTENCODING_UTF16BE, 
			bytes_crlf_utf16be, 82),

		CONFIG(wxTextFileType_Dos, wxFONTENCODING_UTF32LE, 
			bytes_crlf_utf32le, 164),

		CONFIG(wxTextFileType_Dos, wxFONTENCODING_UTF32BE, 
			bytes_crlf_utf32be, 164)
	));


/* MAC OS 9 line endings (har) */
unsigned char bytes_cr_utf16le[78] = {
	0x54, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 
	0x61, 0x00, 0x20, 0x00, 0x6C, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x65, 0x00, 0x2E, 0x00, 
	0x0D, 0x00,
	0x54, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 
	0x61, 0x00, 0x20, 0x00, 0x73, 0x00, 0x65, 0x00, 0x63, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x64, 0x00, 
	0x20, 0x00, 0x6C, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x65, 0x00, 0x2E, 0x00, 
	0x0D, 0x00,
};

unsigned char bytes_cr_utf16be[78] = {
	0x00, 0x54, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20,
	0x00, 0x61, 0x00, 0x20, 0x00, 0x6C, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x65, 0x00, 0x2E,
	0x00, 0x0D,
	0x00, 0x54, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20,
	0x00, 0x61, 0x00, 0x20, 0x00, 0x73, 0x00, 0x65, 0x00, 0x63, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x64,
	0x00, 0x20, 0x00, 0x6C, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x65, 0x00, 0x2E,
	0x00, 0x0D,
};

unsigned char bytes_cr_utf32le[156] = {
	0x54, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 
	0x61, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 
	0x0D, 0x00, 	0x00, 0x00,
	0x54, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 
	0x61, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 
	0x20, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 
	0x0D, 0x00, 	0x00, 0x00,
};

unsigned char bytes_cr_utf32be[156] = {
	0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20,
	0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x2E,
	0x00, 0x00, 0x00, 0x0D,
	0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20,
	0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x64,
	0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x2E,
	0x00, 0x00, 0x00, 0x0D,
};

INSTANTIATE_TEST_CASE_P(CR,
	DocumentLineEndingTest, 
	Values(
		CONFIG(wxTextFileType_Mac, wxFONTENCODING_CP1252,
			"This is a line.\x0DThis is a second line.\x0D", 39),

		CONFIG(wxTextFileType_Mac, wxFONTENCODING_UTF16LE, 
			bytes_cr_utf16le, 78),

		CONFIG(wxTextFileType_Mac, wxFONTENCODING_UTF16BE, 
			bytes_cr_utf16be, 78),

		CONFIG(wxTextFileType_Mac, wxFONTENCODING_UTF32LE, 
			bytes_cr_utf32le, 156),

		CONFIG(wxTextFileType_Mac, wxFONTENCODING_UTF32BE, 
			bytes_cr_utf32be, 156)
	));


/* UNIX line endings */
unsigned char bytes_lf_utf16le[78] = {
	0x54, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 
	0x61, 0x00, 0x20, 0x00, 0x6C, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x65, 0x00, 0x2E, 0x00, 
	0x0A, 0x00,
	0x54, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 
	0x61, 0x00, 0x20, 0x00, 0x73, 0x00, 0x65, 0x00, 0x63, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x64, 0x00, 
	0x20, 0x00, 0x6C, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x65, 0x00, 0x2E, 0x00, 
	0x0A, 0x00,
};

unsigned char bytes_lf_utf16be[78] = {
	0x00, 0x54, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20,
	0x00, 0x61, 0x00, 0x20, 0x00, 0x6C, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x65, 0x00, 0x2E,
	0x00, 0x0A,
	0x00, 0x54, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20,
	0x00, 0x61, 0x00, 0x20, 0x00, 0x73, 0x00, 0x65, 0x00, 0x63, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x64,
	0x00, 0x20, 0x00, 0x6C, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x65, 0x00, 0x2E,
	0x00, 0x0A,
};

unsigned char bytes_lf_utf32le[156] = {
	0x54, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 
	0x61, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 
	0x0A, 0x00, 	0x00, 0x00,
	0x54, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 
	0x61, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 
	0x20, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 
	0x0A, 0x00, 	0x00, 0x00,
};

unsigned char bytes_lf_utf32be[156] = {
	0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20,
	0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x2E,
	0x00, 0x00, 0x00, 0x0A,
	0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x20,
	0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x64,
	0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x2E,
	0x00, 0x00, 0x00, 0x0A,
};

INSTANTIATE_TEST_CASE_P(LF,
	DocumentLineEndingTest, 
	Values(
		CONFIG(wxTextFileType_Unix, wxFONTENCODING_CP1252,
			"This is a line.\x0AThis is a second line.\x0A", 39),

		CONFIG(wxTextFileType_Unix, wxFONTENCODING_UTF16LE, 
			bytes_lf_utf16le, 78),

		CONFIG(wxTextFileType_Unix, wxFONTENCODING_UTF16BE, 
			bytes_lf_utf16be, 78),

		CONFIG(wxTextFileType_Unix, wxFONTENCODING_UTF32LE, 
			bytes_lf_utf32le, 156),

		CONFIG(wxTextFileType_Unix, wxFONTENCODING_UTF32BE, 
			bytes_lf_utf32be, 156)
	));
